#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
拾取窗中流光 - 现代化窗口状态监控工具
功能：监控当前活动窗口、音乐播放状态，并通过Socket.IO推送到Web API
特点：现代化UI、实时日志、智能状态检测
作者：adnaan
"""

import sys
import time
import threading
import configparser
import logging
import queue
from datetime import datetime
from pathlib import Path
from typing import Optional

# 导入应用状态解析器
from app_parser import AppStatusParser

# 兼容性处理 - 解决打包后的distutils问题
try:
    import distutils
except ImportError:
    try:
        import setuptools
        sys.modules['distutils'] = setuptools
        import setuptools.version
        sys.modules['distutils.version'] = setuptools.version
    except ImportError:
        pass

# 系统库
import pystray
from PIL import Image, ImageDraw
from PIL import ImageTk
import psutil
import win32gui
import win32process
import socketio

# 现代化UI库 - ttkbootstrap
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.toast import ToastNotification
from tkinter import scrolledtext, messagebox, Canvas, Label as TkLabel, Listbox, Entry as TkEntry, Checkbutton as TkCheckbutton
from tkinter.constants import END


class ProcessScanner:
    """程序扫描器 - 扫描并管理所有运行的程序（优化版）"""
    
    _cache = None
    _cache_time = None
    _cache_ttl = 10.0  # 缓存10秒，减少扫描频率
    _scanning = False  # 防止并发扫描
    _lock = threading.Lock()  # 线程锁
    
    @classmethod
    def get_all_processes(cls, force_refresh=False):
        """获取所有运行的程序（去重+缓存+线程安全）
        
        Args:
            force_refresh: 是否强制刷新缓存
            
        Returns:
            程序列表
        """
        current_time = time.time()
        
        # 检查缓存（无锁快速路径）
        if not force_refresh and cls._cache is not None and cls._cache_time is not None:
            if current_time - cls._cache_time < cls._cache_ttl:
                return cls._cache
        
        # 使用锁防止并发扫描
        with cls._lock:
            # 双重检查
            if not force_refresh and cls._cache is not None and cls._cache_time is not None:
                if current_time - cls._cache_time < cls._cache_ttl:
                    return cls._cache
            
            if cls._scanning:
                # 如果正在扫描，返回缓存
                return cls._cache or []
            
            cls._scanning = True
        
        try:
            # 扫描进程
            processes = []
            seen_names = set()  # 用于去重
            
            # 只获取必要的信息，减少性能开销
            for proc in psutil.process_iter(['pid', 'name'], ad_value=None):
                try:
                    info = proc.info
                    app_name = info.get('name')
                    
                    # 只添加.exe文件且未添加过的
                    if app_name and app_name.endswith('.exe') and app_name not in seen_names:
                        seen_names.add(app_name)
                        processes.append({
                            'name': app_name,
                            'pid': info.get('pid', 0)
                        })
                except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                    pass
            
            # 更新缓存
            cls._cache = sorted(processes, key=lambda x: x['name'])
            cls._cache_time = current_time
            
            return cls._cache
            
        except Exception as e:
            print(f"扫描程序失败: {e}")
            return cls._cache or []
        finally:
            cls._scanning = False
    
    @classmethod
    def search_processes(cls, query):
        """搜索程序"""
        all_processes = cls.get_all_processes()
        query = query.lower()
        return [p for p in all_processes if query in p['name'].lower()]


class AppConfigManager:
    """应用配置管理器 - 管理监控的应用列表和自定义文案（优化版）"""
    
    def __init__(self, app_parser=None):
        self.config_file = Path('app_config.json')
        self.backup_file = Path('app_config.json.bak')  # 备份文件
        # 格式: {app_key: {'enabled': True, 'custom_template': ''}}
        # app_key 是应用分类中的key（如 'cursor', 'chrome'），而不是完整进程名
        self.monitored_apps = {}
        self.app_parser = app_parser
        self._modified = False  # 跟踪是否有修改
        self.load_config()
    
    def load_config(self):
        """加载配置"""
        import json
        if self.config_file.exists():
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    self.monitored_apps = data.get('monitored_apps', {})
                    return True
            except json.JSONDecodeError as e:
                self.monitored_apps = {}
                return False
            except Exception as e:
                self.monitored_apps = {}
                return False
        return True
    
    def save_config(self, force=False):
        """保存配置（优化版）
        
        Args:
            force: 强制保存，即使没有修改
        """
        import json
        
        if not force and not self._modified:
            return True  # 没有修改，跳过保存
        
        try:
            # 确保目录存在
            self.config_file.parent.mkdir(parents=True, exist_ok=True)
            
            # 备份当前配置
            if self.config_file.exists():
                try:
                    import shutil
                    shutil.copy2(self.config_file, self.backup_file)
                except Exception:
                    pass
            
            # 先写入临时文件，再重命名（原子操作）
            temp_file = self.config_file.with_suffix('.tmp')
            with open(temp_file, 'w', encoding='utf-8') as f:
                json.dump({
                    'monitored_apps': self.monitored_apps,
                    'version': '2.0',
                    'last_modified': datetime.now().isoformat()
                }, f, ensure_ascii=False, indent=2)
            
            # 重命名为正式文件
            temp_file.replace(self.config_file)
            self._modified = False
            return True
        except Exception as e:
            # 尝试从备份恢复
            if self.backup_file.exists():
                try:
                    import shutil
                    shutil.copy2(self.backup_file, self.config_file)
                except Exception:
                    pass
            return False
    
    def get_app_key(self, process_name):
        """从进程名获取应用分类key
        
        Args:
            process_name: 进程名（如 cursor.exe）
            
        Returns:
            应用分类key（如 cursor）或 None
        """
        if not self.app_parser:
            return None
        
        app_key = process_name.lower().replace('.exe', '')
        
        # 在所有分类中查找匹配的key
        for category, apps in self.app_parser.APP_CATEGORIES.items():
            for key, friendly_name in apps.items():
                if key in app_key:
                    return key
        
        return None
    
    def add_app(self, app_key, friendly_name=None):
        """添加应用
        
        Args:
            app_key: 应用分类key（如 'cursor', 'chrome'）
            friendly_name: 友好名称（可选）
        """
        if app_key not in self.monitored_apps:
            self.monitored_apps[app_key] = {
                'enabled': True,
                'custom_template': '',  # 空表示使用默认模板
                'friendly_name': friendly_name or app_key.capitalize()
            }
            self._modified = True
    
    def remove_app(self, app_key):
        """移除应用"""
        if app_key in self.monitored_apps:
            del self.monitored_apps[app_key]
            self._modified = True
    
    def toggle_app(self, app_key):
        """切换应用状态"""
        if app_key in self.monitored_apps:
            self.monitored_apps[app_key]['enabled'] = not self.monitored_apps[app_key]['enabled']
            self._modified = True
    
    def set_custom_template(self, app_key, template):
        """设置自定义文案模板
        
        支持的占位符:
        - {appName} - 应用名称
        - {action} - 动作（编辑/浏览/播放等）
        - {detail} - 详细信息
        - {file_name} - 文件名（编辑器）
        - {project_name} - 项目名（编辑器）
        - {page_title} - 页面标题（浏览器）
        - {song_name} - 歌曲名（音乐）
        - {artist} - 艺术家（音乐）
        
        Args:
            app_key: 应用分类key
            template: 模板字符串
        """
        if app_key in self.monitored_apps:
            old_template = self.monitored_apps[app_key].get('custom_template', '')
            if old_template != template:
                self.monitored_apps[app_key]['custom_template'] = template
                self._modified = True
    
    def format_custom_text(self, app_key, parsed_data):
        """根据模板格式化自定义文案
        
        Args:
            app_key: 应用分类key
            parsed_data: 解析后的数据（包含所有字段）
            
        Returns:
            格式化后的文案
        """
        if app_key not in self.monitored_apps:
            return None
        
        template = self.monitored_apps[app_key].get('custom_template', '')
        if not template:
            return None  # 使用默认
        
        try:
            # 构建可用的占位符数据
            data = {
                'appName': parsed_data.get('appName', ''),
                'action': parsed_data.get('action', ''),
                'detail': parsed_data.get('detail', ''),
                'file_name': parsed_data.get('file_name', ''),
                'project_name': parsed_data.get('project_name', ''),
                'page_title': parsed_data.get('page_title', ''),
                'song_name': parsed_data.get('song_name', ''),
                'artist': parsed_data.get('artist', ''),
            }
            
            result = template.format(**data)
            return result
        except (KeyError, Exception):
            return None


class BeautifulCard:
    """精美卡片组件 - 带渐变和阴影效果"""
    
    def __init__(self, parent, bg_color="#2C3E50", gradient_color="#34495E", 
                 corner_radius=12, shadow=True, padding=15):
        self.parent = parent
        self.bg_color = bg_color
        self.gradient_color = gradient_color
        self.corner_radius = corner_radius
        self.shadow = shadow
        self.padding = padding
        
        # 创建Canvas
        self.canvas = Canvas(
            parent,
            bg="#1A1F2E",
            highlightthickness=0,
            relief="flat",
            borderwidth=0
        )
        
        self.inner_frame = ttk.Frame(self.canvas)
        
    def pack(self, **kwargs):
        """布局"""
        self.canvas.pack(**kwargs)
        self.update_size()
        
    def configure(self, **kwargs):
        """配置"""
        self.canvas.configure(**kwargs)
        
    def update_size(self, width=None, height=None):
        """更新尺寸"""
        self.canvas.update_idletasks()
        if width is None:
            width = self.canvas.winfo_width()
        if height is None:
            height = self.canvas.winfo_height()
        
        # 绘制卡片
        self.canvas.delete("all")
        
        # 阴影效果
        if self.shadow:
            self.canvas.create_oval(
                5, 5, width-5, height-5,
                fill="#0A0E1A", outline="",
                tags="shadow"
            )
        
        # 主卡片背景
        self.canvas.create_rectangle(
            8, 8, width-8, height-8,
            fill=self.bg_color, outline="",
            width=0, tags="card"
        )
        
        # 渐变效果（简化版）
        for i in range(3):
            color = self.gradient_color
            self.canvas.create_rectangle(
                width-8-i*2, 8, width-8-i*2+1, height-8,
                fill=color, outline="",
                tags="gradient"
            )
    
    def get_inner_widget(self):
        """获取内部容器"""
        return self.canvas


class StatusIndicator:
    """精美状态指示器组件"""
    
    def __init__(self, parent, status="online", size=20):
        self.parent = parent
        self.status = status
        self.size = size
        
        self.canvas = Canvas(
            parent,
            width=size,
            height=size,
            highlightthickness=0,
            relief="flat",
            borderwidth=0,
            bg="#1A1F2E"
        )
        
        self.draw_indicator()
        
    def draw_indicator(self):
        """绘制指示器"""
        self.canvas.delete("all")
        
        # 根据状态选择颜色
        colors = {
            "online": ("#4ADE80", "#10B981"),  # 绿色
            "offline": ("#F87171", "#EF4444"),  # 红色
            "warning": ("#FBBF24", "#F59E0B"),  # 黄色
            "info": ("#60A5FA", "#3B82F6"),     # 蓝色
        }
        
        color, outline_color = colors.get(self.status, colors["offline"])
        
        # 外圈
        self.canvas.create_oval(
            3, 3, self.size-3, self.size-3,
            fill=outline_color, outline="",
            tags="outer"
        )
        
        # 内圈
        self.canvas.create_oval(
            7, 7, self.size-7, self.size-7,
            fill=color, outline="",
            tags="inner"
        )
        
        # 发光效果
        self.canvas.create_oval(
            8, 8, self.size-8, self.size-8,
            fill="white", outline="",
            tags="glow"
        )
    
    def set_status(self, status):
        """设置状态"""
        self.status = status
        self.draw_indicator()
    
    def pack(self, **kwargs):
        """布局"""
        self.canvas.pack(**kwargs)
    
    def get_widget(self):
        """获取widget"""
        return self.canvas


class LogManager:
    """日志管理器 - 支持实时日志显示（优化版）"""
    
    def __init__(self, maxsize=500):
        """初始化日志管理器
        
        Args:
            maxsize: 日志队列最大大小，防止内存泄漏
        """
        self.log_queue = queue.Queue(maxsize=maxsize)
        self.log_count = 0  # 日志计数
        self.error_count = 0  # 错误计数
        self.warning_count = 0  # 警告计数
        
        # 配置日志格式
        self.logger = logging.getLogger('StatusMonitor')
        self.logger.setLevel(logging.INFO)
        
        # 清除已有处理器
        self.logger.handlers.clear()
        
        # 创建自定义处理器
        handler = QueueHandler(self.log_queue, self)
        formatter = logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s', 
                                    datefmt='%H:%M:%S')
        handler.setFormatter(formatter)
        self.logger.addHandler(handler)
    
    def get_statistics(self):
        """获取日志统计"""
        return {
            'total': self.log_count,
            'errors': self.error_count,
            'warnings': self.warning_count
        }
    
    def get_logger(self):
        """获取日志器"""
        return self.logger
    
    def get_recent_logs(self, limit=50):
        """获取最近的日志"""
        logs = []
        temp_queue = queue.Queue()
        
        while not self.log_queue.empty() and len(logs) < limit:
            try:
                log_record = self.log_queue.get_nowait()
                logs.append(log_record)
                temp_queue.put(log_record)
            except queue.Empty:
                break
        
        # 将日志放回队列
        while not temp_queue.empty():
            self.log_queue.put(temp_queue.get())
        
        return logs[-limit:] if logs else []


class QueueHandler(logging.Handler):
    """队列处理器 - 将日志放入队列（优化版）"""
    
    def __init__(self, log_queue, log_manager=None):
        super().__init__()
        self.log_queue = log_queue
        self.log_manager = log_manager
    
    def emit(self, record):
        try:
            formatted = self.format(record)
            
            # 统计日志
            if self.log_manager:
                self.log_manager.log_count += 1
                if record.levelno >= logging.ERROR:
                    self.log_manager.error_count += 1
                elif record.levelno >= logging.WARNING:
                    self.log_manager.warning_count += 1
            
            # 使用 put_nowait，如果队列满则丢弃旧日志
            try:
                self.log_queue.put_nowait(formatted)
            except queue.Full:
                # 队列满时，移除最旧的日志
                try:
                    self.log_queue.get_nowait()
                    self.log_queue.put_nowait(formatted)
                except (queue.Empty, queue.Full):
                    pass
        except Exception:
            self.handleError(record)


class StatusMonitor:
    """状态监控核心类（优化版）"""
    
    def __init__(self, log_manager: LogManager, app_config_manager=None):
        self.log_manager = log_manager
        self.logger = log_manager.get_logger()
        self.config = self.load_config()
        
        # 应用状态解析器
        self.app_parser = AppStatusParser()
        
        # 应用配置管理器（传递parser用于智能匹配）
        self.app_config_manager = app_config_manager or AppConfigManager(self.app_parser)
        
        # 状态数据
        self.current_status = {
            'active_app': '',
            'timestamp': '',
            'computer_name': ''
        }
        
        # 运行状态
        self.running = False
        self.monitor_thread = None
        self._last_push_time = None
        self._last_status_print = None
        self._stop_event = threading.Event()  # 停止事件
        
        # 统计数据
        self.statistics = {
            'push_count': 0,  # 推送次数
            'push_success': 0,  # 成功推送
            'push_failed': 0,  # 失败推送
            'app_switches': 0,  # 应用切换次数
            'start_time': None,  # 启动时间
            'uptime': 0,  # 运行时长
            'last_push_time': None,  # 最后推送时间
        }
        
        # 监控配置已通过 app_config_manager.monitored_apps 管理
        
        # Socket.IO客户端
        # 使用 reconnection=True 让 socketio 自己管理重连，避免并发问题
        self.sio = socketio.Client(
            logger=False, 
            engineio_logger=False, 
            reconnection=True,
            reconnection_attempts=15,
            reconnection_delay=2,
            reconnection_delay_max=60
        )
        self.socket_connected = False
        self.reconnect_count = 0
        self.max_reconnect_attempts = 15
        self.reconnect_delay = 2.0
        self.last_heartbeat = None
        self.heartbeat_interval = 30.0
        self.connection_timeout = 15.0
        self._heartbeat_timer = None
        self._reconnect_timer = None
        self._disconnect_handling = False  # 防止重复处理断开
        self.setup_socket_events()
        
        self.logger.info("🚀 拾取窗中流光初始化完成")
        
    def load_config(self):
        """加载配置文件"""
        config = configparser.ConfigParser()
        config_file = Path('config.ini')
        
        if not config_file.exists():
            config['SERVER'] = {
                'server_url': 'http://localhost:3001',
                'auth_key': 'duyong-socket-328'
            }
            
            with open(config_file, 'w', encoding='utf-8') as f:
                config.write(f)
            
            self.logger.info("📁 创建默认配置文件")
        
        config.read(config_file, encoding='utf-8')
        return config
    
    def setup_socket_events(self):
        """设置Socket.IO事件处理"""
        @self.sio.event
        def connect():
            self.logger.info("🔌 Socket.IO连接成功")
            self.socket_connected = True
            self.reconnect_count = 0
            self.last_heartbeat = time.time()
            self.start_heartbeat()
        
        @self.sio.event
        def disconnect():
            # 使用标志防止重复处理
            if self._disconnect_handling:
                return
            
            self._disconnect_handling = True
            
            def handle_disconnect():
                try:
                    self.logger.warning("🔌 Socket.IO连接断开")
                    self.socket_connected = False
                    self.stop_heartbeat()
                    # socketio 已启用自动重连，无需手动重连
                except Exception as e:
                    self.logger.error(f"断开连接处理错误: {e}")
                finally:
                    # 延迟重置标志
                    threading.Timer(2.0, lambda: setattr(self, '_disconnect_handling', False)).start()
            
            # 延迟处理避免与 socketio 内部逻辑冲突
            threading.Timer(0.1, handle_disconnect).start()
        
        @self.sio.event
        def connect_error(data):
            def handle_error():
                try:
                    self.logger.error(f"❌ Socket.IO连接错误: {data}")
                    self.socket_connected = False
                    self.stop_heartbeat()
                    # socketio 已启用自动重连
                except Exception as e:
                    self.logger.error(f"连接错误处理失败: {e}")
            
            # 延迟处理避免与 socketio 内部逻辑冲突
            threading.Timer(0.1, handle_error).start()
        
        @self.sio.on('heartbeat_ack')
        def on_heartbeat_ack(data):
            self.last_heartbeat = time.time()
        
        @self.sio.on('status:push:result')
        def on_push_result(data):
            if data.get('success'):
                if data.get('changed'):
                    self.logger.info("✅ 状态推送成功")
                else:
                    self.logger.info("📋 状态无变化")
            else:
                self.logger.error(f"❌ 状态推送失败: {data.get('message', '未知错误')}")
    
    def start_heartbeat(self):
        """启动心跳检测"""
        def send_heartbeat():
            if self.socket_connected and self.sio.connected:
                try:
                    self.sio.emit('heartbeat', {'timestamp': int(time.time() * 1000)})
                    
                    if self.last_heartbeat and time.time() - self.last_heartbeat > 90:
                        self.logger.warning("⚠️ 心跳超时，重新连接")
                        self.socket_connected = False
                        self.disconnect_socket()
                        self.schedule_reconnect()
                        return
                    
                except Exception as e:
                    self.logger.error(f"❌ 心跳发送失败: {e}")
                    self.socket_connected = False
                    self.schedule_reconnect()
                    return
                
                self._heartbeat_timer = threading.Timer(self.heartbeat_interval, send_heartbeat)
                self._heartbeat_timer.daemon = True
                self._heartbeat_timer.start()
        
        if self._heartbeat_timer:
            self._heartbeat_timer.cancel()
        send_heartbeat()
    
    def stop_heartbeat(self):
        """停止心跳检测"""
        if self._heartbeat_timer:
            self._heartbeat_timer.cancel()
            self._heartbeat_timer = None
    
    def schedule_reconnect(self):
        """安排重连"""
        if self._reconnect_timer:
            self._reconnect_timer.cancel()
        
        if self.reconnect_count >= self.max_reconnect_attempts:
            self.logger.error("❌ 达到最大重连次数，停止重连")
            return
        
        self.reconnect_count += 1
        delay = min(self.reconnect_delay * (2 ** (self.reconnect_count - 1)), 60)
        
        self.logger.info(f"🔄 {delay:.1f}秒后尝试第{self.reconnect_count}次重连")
        
        def do_reconnect():
            if not self.socket_connected:
                self.connect_socket()
        
        self._reconnect_timer = threading.Timer(delay, do_reconnect)
        self._reconnect_timer.daemon = True
        self._reconnect_timer.start()
    
    def connect_socket(self):
        """连接到Socket.IO服务器"""
        try:
            server_url = self.config.get('SERVER', 'server_url', fallback='http://localhost:3001')
            if not server_url:
                self.logger.error("❌ 未配置服务器地址")
                return False
            
            if not server_url.startswith(('http://', 'https://')):
                if 'localhost' in server_url or '127.0.0.1' in server_url:
                    server_url = 'http://' + server_url
                else:
                    server_url = 'https://' + server_url
            
            self.logger.info(f"🔗 连接Socket.IO: {server_url}")
            
            if self.sio.connected:
                try:
                    self.sio.disconnect()
                    time.sleep(0.5)
                except:
                    pass
            
            auth_token = self.config.get('SERVER', 'auth_key', fallback='duyong-socket-328')
            
            connect_kwargs = {
                'transports': ['polling', 'websocket'],
                'wait_timeout': self.connection_timeout,
                'auth': {
                    'token': auth_token,
                    'client_type': 'status_monitor',
                    'version': '2.0'
                },
                'headers': {
                    'User-Agent': 'StatusMonitor/2.0-Python',
                    'Authorization': auth_token,
                }
            }
            
            self.sio.connect(server_url, **connect_kwargs)
            
            start_time = time.time()
            while not self.sio.connected and time.time() - start_time < self.connection_timeout:
                time.sleep(0.1)
            
            if self.sio.connected:
                self.logger.info("✅ Socket.IO连接建立成功")
                self.socket_connected = True
                return True
            else:
                self.logger.error("❌ Socket.IO连接超时")
                return False
                
        except Exception as e:
            self.logger.error(f"❌ Socket.IO连接异常: {e}")
            self.socket_connected = False
            return False
    
    def disconnect_socket(self):
        """断开Socket.IO连接"""
        try:
            self.stop_heartbeat()
            if self._reconnect_timer:
                self._reconnect_timer.cancel()
                self._reconnect_timer = None
            
            self.socket_connected = False
            
            if self.sio:
                # 使用线程安全的方式断开连接
                def safe_disconnect():
                    try:
                        if self.sio.connected:
                            self.sio.disconnect()
                            self.logger.info("🔌 Socket.IO连接已断开")
                    except RuntimeError as e:
                        # 捕获socketio的并发错误（字典迭代问题）
                        self.logger.warning(f"断开连接时发生并发错误（已忽略）: {e}")
                    except Exception as e:
                        self.logger.warning(f"断开连接时出错: {e}")
                
                # 延迟执行避免并发
                threading.Timer(0.1, safe_disconnect).start()
            
        except Exception as e:
            self.logger.error(f"断开连接时出错: {e}")
        finally:
            self.socket_connected = False
    
    def get_active_window_info(self):
        """获取当前活动窗口信息"""
        try:
            hwnd = win32gui.GetForegroundWindow()
            if hwnd:
                window_text = win32gui.GetWindowText(hwnd)
                _, pid = win32process.GetWindowThreadProcessId(hwnd)
                try:
                    process = psutil.Process(pid)
                    app_name = process.name()
                    return {
                        'app_name': app_name,
                        'window_title': window_text
                    }
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    return None
        except Exception as e:
            self.logger.error(f"获取窗口信息失败: {e}")
            return None
    
    def send_status_to_web(self, status_data):
        """发送状态到Web API（使用Socket.IO）"""
        self.statistics['push_count'] += 1
        
        try:
            if not self.socket_connected:
                self.logger.warning("⚠️ Socket.IO未连接，尝试重新连接...")
                if not self.connect_socket():
                    self.logger.error("❌ 无法建立Socket.IO连接")
                    self.statistics['push_failed'] += 1
                    return
                time.sleep(0.5)
            
            if self.sio.connected:
                self.sio.emit('status:push', status_data)
                self.logger.info(f"📡 状态已推送: {datetime.now().strftime('%H:%M:%S')}")
                self.statistics['push_success'] += 1
                self.statistics['last_push_time'] = datetime.now()
                
                # 增加推送计数（供GUI使用）
                if hasattr(self, 'push_count_ref'):
                    self.push_count_ref[0] += 1
            else:
                self.logger.error("❌ Socket.IO连接已断开")
                self.statistics['push_failed'] += 1
                
        except Exception as e:
            self.logger.error(f"推送状态失败: {e}")
            self.socket_connected = False
            self.statistics['push_failed'] += 1
    
    def get_statistics(self):
        """获取统计信息"""
        if self.statistics['start_time']:
            self.statistics['uptime'] = (datetime.now() - self.statistics['start_time']).total_seconds()
        
        return {
            **self.statistics,
            'success_rate': (self.statistics['push_success'] / self.statistics['push_count'] * 100) 
                if self.statistics['push_count'] > 0 else 0
        }
    
    def should_monitor_app(self, app_key):
        """判断是否应该监控该应用
        
        Args:
            app_key: 应用分类key
            
        Returns:
            是否应该监控
        """
        # 检查是否在监控列表中且已启用
        if app_key in self.app_config_manager.monitored_apps:
            app_config = self.app_config_manager.monitored_apps[app_key]
            return app_config.get('enabled', True)
        
        return False
    
    def monitor_loop(self):
        """监控循环（优化版）"""
        self.logger.info("🔍 开始监控循环")
        self.statistics['start_time'] = datetime.now()
        
        while self.running and not self._stop_event.is_set():
            try:
                app_info = self.get_active_window_info()
                
                if app_info and app_info.get('app_name') and app_info.get('window_title'):
                    # 解析应用状态
                    parsed_status = self.app_parser.parse_app_status(
                        app_info['app_name'],
                        app_info['window_title']
                    )
                    
                    app_key = parsed_status.get('appKey')
                    if not app_key:
                        time.sleep(1)
                        continue
                    
                    # 检查是否应该监控该应用
                    if not self.should_monitor_app(app_key):
                        time.sleep(1)
                        continue
                    
                    # 尝试使用自定义文案模板
                    custom_text = self.app_config_manager.format_custom_text(app_key, parsed_status)
                    
                    # 调试日志
                    if custom_text:
                        self.logger.debug(f"✅ 使用自定义模板: {custom_text}")
                    else:
                        self.logger.debug(f"📄 使用默认文案: {parsed_status['detail']}")
                        self.logger.debug(f"   可用字段: file_name={parsed_status.get('file_name')}, project_name={parsed_status.get('project_name')}")
                    
                    display_detail = custom_text if custom_text else parsed_status['detail']
                    
                    # 获取自定义的 action（如果有）
                    custom_action = None
                    if app_key in self.app_config_manager.monitored_apps:
                        custom_action = self.app_config_manager.monitored_apps[app_key].get('custom_action')
                    
                    # 使用自定义 action 或解析器识别的 action
                    final_action = custom_action if custom_action and custom_action != '自动' else parsed_status['action']
                    
                    new_status = {
                        'active_app': parsed_status['displayInfo'],
                        'timestamp': datetime.now().isoformat(),
                        'computer_name': psutil.users()[0].name if psutil.users() else 'Unknown',
                        'appName': parsed_status['appName'],
                        'appIcon': parsed_status['appIcon'],
                        'appType': parsed_status['appType'],
                        'displayInfo': display_detail,  # 使用自定义或默认文案
                        'action': final_action,  # 使用自定义或自动识别的 action
                    }
                    
                    previous_app = self.current_status.get('active_app', '')
                    current_app = new_status['active_app']
                    
                    if current_app and current_app != previous_app:
                        self.statistics['app_switches'] += 1
                        current_time = time.time()
                        if self._last_push_time is None or current_time - self._last_push_time >= 2:
                            self.logger.info("📊 检测到应用变化")
                            self.logger.info(f"  🔄 {parsed_status['appName']} {parsed_status['action']}")
                            self.logger.info(f"  📄 {parsed_status['detail']}")
                            
                            self.current_status = new_status
                            self.send_status_to_web(new_status)
                            self._last_push_time = current_time
                        else:
                            self.current_status = new_status
                
                current_time = time.time()
                if self._last_status_print is None or current_time - self._last_status_print > 120:
                    status_text = self.current_status.get('appName', '无活动')
                    self.logger.info(f"📋 当前状态: {status_text}")
                    self._last_status_print = current_time
                
                # 使用事件等待而不是sleep，可以快速响应停止信号
                self._stop_event.wait(1)
                
            except KeyboardInterrupt:
                self.logger.info("🛑 收到中断信号")
                break
            except Exception as e:
                self.logger.error(f"监控循环错误: {e}")
                import traceback
                self.logger.debug(traceback.format_exc())
                # 错误后等待更长时间再重试
                self._stop_event.wait(5)
    
    def start_monitoring(self):
        """开始监控"""
        if not self.running:
            self.logger.info("🔗 准备启动状态监控...")
            
            self.logger.info("🔗 正在连接Socket.IO服务器...")
            if self.connect_socket():
                self.running = True
                self.monitor_thread = threading.Thread(target=self.monitor_loop, daemon=True)
                self.monitor_thread.start()
                self.logger.info("✅ 状态监控已启动")
                return True
            else:
                self.logger.error("❌ 无法连接到Socket.IO服务器")
                return False
        return True
    
    def stop_monitoring(self):
        """停止监控（优化版）"""
        self.running = False
        self._stop_event.set()  # 设置停止事件
        
        if self.monitor_thread and self.monitor_thread.is_alive():
            self.monitor_thread.join(timeout=3)
            if self.monitor_thread.is_alive():
                self.logger.warning("⚠️ 监控线程未能正常停止")
        
        self.disconnect_socket()
        self.logger.info("🛑 状态监控已停止")
        
        # 记录运行统计
        stats = self.get_statistics()
        self.logger.info(f"📊 运行统计: 推送 {stats['push_count']} 次, "
                        f"成功 {stats['push_success']} 次, "
                        f"成功率 {stats['success_rate']:.1f}%")


class ModernConfigWindow:
    """现代化配置窗口 - 使用ttkbootstrap"""
    
    def __init__(self, monitor: StatusMonitor, log_manager: LogManager, root_window=None):
        self.monitor = monitor
        self.log_manager = log_manager
        self.logger = log_manager.get_logger()
        self.config = monitor.config
        self.config_file = Path('config.ini')
        self.root_window = root_window
        
        # 共享推送计数
        self.push_count = [0]
        monitor.push_count_ref = self.push_count
        
        # 使用monitor的配置管理器（共享的）
        self.app_config_manager = monitor.app_config_manager
        
        # 创建窗口 - 无边框现代化风格
        if root_window:
            self.window = ttk.Toplevel(root_window)
        else:
            self.window = ttk.Window(
                title="✨ 拾取窗中流光",
                themename="litera",
                size=(1100, 750),
                minsize=(900, 600)
            )
        
        self.window.title("✨ 拾取窗中流光")
        self.window.geometry("1100x750")
        self.window.minsize(900, 600)
        
        # 去掉Windows原生标题栏，使用自定义标题栏
        self.window.overrideredirect(True)  # 去掉系统标题栏
        
        self.window.configure(bg="#FFFFFF")
        
        # 设置窗口图标
        self.set_window_icon()
        
        # 居中显示（需要手动计算，因为overrideredirect后无法使用place_window_center）
        self.center_window()
        
        # 初始化拖动变量
        self.drag_x = 0
        self.drag_y = 0
        
        # 设置窗口关闭协议
        self.window.protocol("WM_DELETE_WINDOW", self.hide_window)
        
        # 绑定快捷键
        self.window.bind('<Escape>', lambda e: self.hide_window())  # ESC隐藏窗口
        self.window.bind('<Control-s>', lambda e: self.save_config())  # Ctrl+S保存
        self.window.bind('<F5>', lambda e: self.refresh_app_list(force=True))  # F5刷新
        
        # 日志更新
        self.log_text = None
        
        # 创建界面
        self.create_modern_ui()
        
        # 开始日志更新
        self.start_log_updates()
        
        self.logger.info("🎨 现代化配置界面已启动")
    
    def set_window_icon(self):
        """设置窗口图标"""
        try:
            icon_paths = [
                Path(__file__).parent / 'icon.ico',
                Path(__file__).parent.parent / 'icon.ico',
                Path('icon.ico')
            ]
            
            for icon_path in icon_paths:
                if isinstance(icon_path, Path) and icon_path.exists():
                    self.window.iconbitmap(str(icon_path))
                    break
        except Exception as e:
            self.logger.warning(f"设置图标失败: {e}")
    
    def create_modern_ui(self):
        """创建清新简约的现代化UI"""
        # 自定义标题栏容器
        title_bar_container = ttk.Frame(self.window, style="Title.TFrame")
        title_bar_container.pack(fill=X)
        
        # 标题容器
        title_container = ttk.Frame(title_bar_container)
        title_container.pack(fill=X, padx=10, pady=5)
        
        # 加载并显示图标
        try:
            icon_paths = [
                Path(__file__).parent / 'icon.ico',
                Path(__file__).parent.parent / 'icon.ico',
                Path('icon.ico')
            ]
            
            icon_image = None
            for icon_path in icon_paths:
                if icon_path.exists():
                    img = Image.open(icon_path)
                    img = img.resize((24, 24), Image.Resampling.LANCZOS)
                    icon_image = ImageTk.PhotoImage(img)
                    break
            
            if icon_image:
                icon_label = TkLabel(title_container, image=icon_image, bg=self.window.cget('bg'))
                icon_label.image = icon_image  # 保持引用
                icon_label.pack(side=LEFT, padx=(0, 8))
        except Exception as e:
            self.logger.warning(f"加载图标失败: {e}")
        
        # 标题文字
        title_label = ttk.Label(
            title_container,
            text="拾取窗中流光",
            font=("Microsoft YaHei UI", 13, "bold")
        )
        title_label.pack(side=LEFT)
        
        # 标题栏按钮区域
        btn_container = ttk.Frame(title_container)
        btn_container.pack(side=RIGHT)
        
        def minimize_window(event=None):
            self.window.withdraw()
        
        ttk.Button(
            btn_container, 
            text="━", 
            command=minimize_window, 
            width=4,
            style="Title.TButton"
        ).pack(side=LEFT, padx=2)
        
        ttk.Button(
            btn_container, 
            text="✕", 
            command=self.hide_window, 
            width=4,
            style="Title.TButton"
        ).pack(side=LEFT, padx=2)
        
        # 设置拖动 - 绑定到所有标题栏元素
        for widget in [title_bar_container, title_container, title_label]:
            widget.bind("<Button-1>", self.start_drag)
            widget.bind("<B1-Motion>", self.on_drag)
        
        # 分割线
        ttk.Separator(self.window, orient='horizontal').pack(fill=X, padx=0)
        
        # 主容器 - 减少内边距
        main_container = ttk.Frame(self.window, padding="15")
        main_container.pack(fill=BOTH, expand=YES)
        
        # 状态栏 - 减小间距
        status_bar = ttk.Frame(main_container)
        status_bar.pack(fill=X, pady=(0, 8))
        
        # 状态标签
        status_left = ttk.Frame(status_bar)
        status_left.pack(side=LEFT, fill=BOTH, expand=YES)
        
        self.status_label = ttk.Label(
            status_left,
            text="🟢 监控已启动",
            font=("Microsoft YaHei UI", 9),
            bootstyle="success"
        )
        self.status_label.pack(side=LEFT, padx=(0, 10))
        
        self.push_count_label = ttk.Label(
            status_left,
            text="📊 推送: 0 次 | 成功率: 0%",
            font=("Microsoft YaHei UI", 9),
            bootstyle="info"
        )
        self.push_count_label.pack(side=LEFT, padx=(0, 10))
        
        self.uptime_label = ttk.Label(
            status_left,
            text="⏱️ 运行: 0秒",
            font=("Microsoft YaHei UI", 9),
            bootstyle="secondary"
        )
        self.uptime_label.pack(side=LEFT)
        
        # 操作按钮
        status_right = ttk.Frame(status_bar)
        status_right.pack(side=RIGHT)
        
        self.start_btn = ttk.Button(
            status_right,
            text="⏸️ 暂停",
            command=self.toggle_monitoring,
            bootstyle="warning-outline",
            width=10
        )
        self.start_btn.pack(side=LEFT, padx=(0, 5))
        
        # 内容区域 - Notebook - 减少expand，添加最大高度
        notebook = ttk.Notebook(main_container, bootstyle="primary")
        notebook.pack(fill=BOTH, expand=YES, pady=(0, 10))
        
        # 标签页
        self.create_app_manager_tab(notebook)
        self.create_connection_tab(notebook)
        self.create_log_tab(notebook)
        
        # 底部按钮 - 固定在底部
        button_frame = ttk.Frame(main_container)
        button_frame.pack(fill=X, pady=(5, 0))
        
        ttk.Button(
            button_frame,
            text="💾 保存配置",
            command=self.save_config,
            bootstyle="success",
            width=12
        ).pack(side=LEFT, padx=(0, 8))
        
        ttk.Button(
            button_frame,
            text="🔽 隐藏窗口",
            command=self.hide_window,
            bootstyle="secondary",
            width=12
        ).pack(side=RIGHT)
        
        # 开始状态更新
        self.update_status_display()
    
    def create_app_manager_tab(self, parent):
        """创建应用管理标签页 - 清新简约风格"""
        tab = ttk.Frame(parent, padding=12)
        parent.add(tab, text="🎯 应用管理")
        
        # 左侧：程序列表
        left_frame = ttk.Labelframe(tab, text="选择要监控的程序", padding=10)
        left_frame.pack(side=LEFT, fill=BOTH, expand=YES, padx=(0, 8))
        
        # 搜索框
        search_frame = ttk.Frame(left_frame)
        search_frame.pack(fill=X, pady=(0, 8))
        
        ttk.Label(search_frame, text="🔍 搜索:", font=("Microsoft YaHei UI", 9)).pack(side=LEFT, padx=(0, 5))
        
        self.search_var = ttk.StringVar()
        search_entry = ttk.Entry(search_frame, textvariable=self.search_var, width=25)
        search_entry.pack(side=LEFT, expand=YES, fill=X, padx=(0, 5))
        
        # 绑定搜索事件
        self.search_var.trace('w', lambda *args: self.search_apps())
        
        ttk.Button(search_frame, text="刷新", command=lambda: self.refresh_app_list(force=True), width=8).pack()
        
        # 程序列表
        list_frame = ttk.Frame(left_frame)
        list_frame.pack(fill=BOTH, expand=YES)
        
        scrollbar = ttk.Scrollbar(list_frame, orient="vertical")
        scrollbar.pack(side=RIGHT, fill=Y)
        
        self.app_listbox = Listbox(list_frame, yscrollcommand=scrollbar.set, font=("Consolas", 9), selectmode="extended")
        self.app_listbox.pack(fill=BOTH, expand=YES)
        scrollbar.config(command=self.app_listbox.yview)
        
        # 操作按钮
        action_btn_frame = ttk.Frame(left_frame)
        action_btn_frame.pack(fill=X, pady=(8, 0))
        
        # 添加到监控按钮
        ttk.Button(
            action_btn_frame, 
            text="➕ 添加到监控", 
            command=self.add_selected_apps, 
            bootstyle="success", 
            width=14
        ).pack(side=LEFT, padx=(0, 5))
        ttk.Button(action_btn_frame, text="🔍 清除搜索", command=lambda: self.search_var.set(""), width=12).pack(side=LEFT)
        
        # 右侧：已选列表和自定义模板
        right_frame = ttk.Labelframe(tab, text="已选程序 & 自定义模板", padding=10)
        right_frame.pack(side=RIGHT, fill=BOTH, expand=YES, padx=(8, 0))
        
        # 已选程序列表
        selected_frame = ttk.Frame(right_frame)
        selected_frame.pack(fill=BOTH, expand=YES)
        
        # 标题和操作按钮
        title_frame = ttk.Frame(selected_frame)
        title_frame.pack(fill=X, pady=(0, 3))
        
        ttk.Label(title_frame, text="已选程序:", font=("Microsoft YaHei UI", 10, "bold")).pack(side=LEFT)
        
        ttk.Button(
            title_frame,
            text="✅ 全选",
            command=self.select_all_apps,
            width=6
        ).pack(side=RIGHT, padx=(2, 0))
        
        ttk.Button(
            title_frame,
            text="❌ 反选",
            command=self.deselect_all_apps,
            width=6
        ).pack(side=RIGHT, padx=2)
        
        self.selected_listbox = Listbox(selected_frame, height=4, font=("Consolas", 9))
        self.selected_listbox.pack(fill=BOTH, expand=YES, pady=(0, 0))
        self.selected_listbox.bind('<<ListboxSelect>>', self.on_app_select)
        
        # 模板示例显示
        ttk.Label(right_frame, text="模板示例:", font=("Microsoft YaHei UI", 10, "bold")).pack(anchor=W, pady=(0, 3))
        
        self.default_text_label = ttk.Label(
            right_frame, 
            text="点击左侧程序查看模板示例",
            font=("Consolas", 7),
            bootstyle="secondary",
            wraplength=300,
            justify="left"
        )
        self.default_text_label.pack(anchor=W, pady=(0, 3))
        
        # 自定义模板编辑
        ttk.Label(right_frame, text="自定义推送模板:", font=("Microsoft YaHei UI", 10, "bold")).pack(anchor=W, pady=(0, 3))
        
        # 占位符说明
        placeholder_text = "可用占位符: {appName} {action} {detail} {file_name} {project_name} {page_title} {song_name} {artist}"
        ttk.Label(
            right_frame,
            text=placeholder_text,
            font=("Consolas", 7),
            bootstyle="info",
            wraplength=300
        ).pack(anchor=W, pady=(0, 2))
        
        # 模板库按钮
        template_btn_frame = ttk.Frame(right_frame)
        template_btn_frame.pack(fill=X, pady=(0, 3))
        
        ttk.Label(template_btn_frame, text="快速模板:", font=("Microsoft YaHei UI", 8)).pack(side=LEFT, padx=(0, 5))
        
        ttk.Button(
            template_btn_frame,
            text="简洁",
            command=lambda: self.apply_template("{appName} {action}"),
            width=8
        ).pack(side=LEFT, padx=2)
        
        ttk.Button(
            template_btn_frame,
            text="详细",
            command=lambda: self.apply_template("{appName} {action}: {detail}"),
            width=8
        ).pack(side=LEFT, padx=2)
        
        ttk.Button(
            template_btn_frame,
            text="编辑器",
            command=lambda: self.apply_template("编辑 {file_name} ({project_name})"),
            width=8
        ).pack(side=LEFT, padx=2)
        
        ttk.Button(
            template_btn_frame,
            text="音乐",
            command=lambda: self.apply_template("🎵 {song_name} - {artist}"),
            width=8
        ).pack(side=LEFT, padx=2)
        
        self.custom_text_var = ttk.StringVar()
        # 绑定实时预览
        self.custom_text_var.trace('w', self.on_template_change)
        
        custom_entry = ttk.Entry(right_frame, textvariable=self.custom_text_var, width=40, font=("Consolas", 9))
        custom_entry.pack(fill=X, pady=(0, 3))
        custom_entry.bind('<Return>', self.save_custom_text)
        custom_entry.bind('<FocusOut>', self.save_custom_text)
        
        # 实时预览标签
        self.preview_label = ttk.Label(
            right_frame,
            text="💡 提示: 输入模板后按回车保存",
            font=("Microsoft YaHei UI", 8),
            bootstyle="info",
            wraplength=300
        )
        self.preview_label.pack(fill=X, pady=(0, 2))
        
        ttk.Button(right_frame, text="💾 保存模板", command=self.save_custom_text, bootstyle="info", width=15).pack(anchor=W, pady=(0, 3))
        
        # 动作状态选择
        action_frame = ttk.Frame(right_frame)
        action_frame.pack(fill=X, pady=(3, 0))
        
        ttk.Label(action_frame, text="动作状态:", font=("Microsoft YaHei UI", 8)).pack(side=LEFT, padx=(0, 5))
        
        self.action_var = ttk.StringVar(value="自动")
        action_combo = ttk.Combobox(
            action_frame,
            textvariable=self.action_var,
            values=["自动", "编辑", "浏览", "播放", "使用中"],
            state="readonly",
            width=10
        )
        action_combo.pack(side=LEFT, padx=(0, 5))
        
        ttk.Label(action_frame, text="💡 自动: 根据窗口标题智能识别", font=("Microsoft YaHei UI", 7), bootstyle="info").pack(side=LEFT)
        
        # 操作按钮区
        btn_frame = ttk.Frame(right_frame)
        btn_frame.pack(fill=X, pady=(3, 0))
        
        ttk.Button(btn_frame, text="🧪 测试推送", command=self.test_push, bootstyle="warning", width=15).pack(side=LEFT, padx=(0, 5))
        ttk.Button(btn_frame, text="➖ 删除选中", command=self.remove_selected_app, bootstyle="danger", width=15).pack(side=LEFT)
        
        # 加载程序列表
        self.refresh_app_list()
        
        # 加载已选程序
        self.load_selected_apps()
    
    def select_all_apps(self):
        """全选所有应用"""
        self.selected_listbox.selection_set(0, END)
    
    def deselect_all_apps(self):
        """反选所有应用"""
        self.selected_listbox.selection_clear(0, END)
    
    def load_selected_apps(self):
        """加载已选程序列表"""
        self.selected_listbox.delete(0, END)
        
        # 如果配置为空，自动添加解析器中配置好的所有应用
        if not self.app_config_manager.monitored_apps:
            for category, apps in self.monitor.app_parser.APP_CATEGORIES.items():
                for app_key, friendly_name in apps.items():
                    self.app_config_manager.add_app(app_key, friendly_name)
                    # 显示格式: friendly_name (app_key)
                    display_text = f"{friendly_name} ({app_key})"
                    self.selected_listbox.insert(END, display_text)
            
            self.app_config_manager.save_config()
        else:
            # 加载已保存的配置
            for app_key, config in self.app_config_manager.monitored_apps.items():
                friendly_name = config.get('friendly_name', app_key.capitalize())
                display_text = f"{friendly_name} ({app_key})"
                self.selected_listbox.insert(END, display_text)
    
    def refresh_app_list(self, force=False):
        """刷新程序列表
        
        Args:
            force: 是否强制刷新（清除缓存）
        """
        self.app_listbox.delete(0, END)
        processes = ProcessScanner.get_all_processes(force_refresh=force)
        for proc in processes:
            self.app_listbox.insert(END, proc['name'])
    
    def search_apps(self):
        """搜索应用程序"""
        try:
            query = self.search_var.get().strip()
            self.app_listbox.delete(0, END)
            
            if not query:
                # 如果搜索框为空，显示所有程序
                processes = ProcessScanner.get_all_processes()
                for proc in processes:
                    self.app_listbox.insert(END, proc['name'])
            else:
                # 搜索匹配的程序
                matched_processes = ProcessScanner.search_processes(query)
                if matched_processes:
                    for proc in matched_processes:
                        self.app_listbox.insert(END, proc['name'])
                else:
                    self.app_listbox.insert(END, "未找到匹配的程序")
        except Exception as e:
            self.logger.error(f"❌ 搜索失败: {e}")
    
    def add_selected_apps(self):
        """添加选中的程序"""
        try:
            selected = self.app_listbox.curselection()
            
            if not selected:
                self.logger.warning("⚠️ 请先选择要添加的程序")
                return
            
            added_count = 0
            last_added_index = -1
            
            for idx in selected:
                process_name = self.app_listbox.get(idx)
                
                # 跳过提示信息
                if process_name == "未找到匹配的程序":
                    continue
                
                # 从进程名获取应用key
                app_key = self.app_config_manager.get_app_key(process_name)
                
                # 如果无法识别，使用进程名作为 app_key
                if not app_key:
                    app_key = process_name.lower().replace('.exe', '')
                
                # 获取友好名称
                friendly_name = None
                for category, apps in self.monitor.app_parser.APP_CATEGORIES.items():
                    if app_key in apps:
                        friendly_name = apps[app_key]
                        break
                
                # 如果没有友好名称，使用进程名（去掉.exe）
                if not friendly_name:
                    friendly_name = process_name.replace('.exe', '')
                
                if app_key not in self.app_config_manager.monitored_apps:
                    self.app_config_manager.add_app(app_key, friendly_name)
                    display_text = f"{friendly_name} ({app_key})"
                    self.selected_listbox.insert(END, display_text)
                    last_added_index = self.selected_listbox.size() - 1
                    added_count += 1
                    self.logger.info(f"✅ 已添加: {friendly_name}")
                else:
                    self.logger.info(f"⚠️ 已存在: {friendly_name}")
            
            if added_count > 0:
                self.app_config_manager.save_config()
                
                # 自动选中最后添加的应用，触发模板加载
                if last_added_index >= 0:
                    self.selected_listbox.selection_clear(0, END)
                    self.selected_listbox.selection_set(last_added_index)
                    self.selected_listbox.see(last_added_index)
                    # 手动触发选择事件
                    self.selected_listbox.event_generate('<<ListboxSelect>>')
                
                self.logger.info(f"✅ 成功添加 {added_count} 个应用")
        except Exception as e:
            self.logger.error(f"❌ 添加应用失败: {e}")
    
    def remove_selected_app(self):
        """移除程序"""
        selected = self.selected_listbox.curselection()
        if selected:
            display_text = self.selected_listbox.get(selected[0])
            # 从显示文本中提取app_key (格式: "Cursor (cursor)")
            import re
            match = re.search(r'\(([^)]+)\)$', display_text)
            if match:
                app_key = match.group(1)
                self.app_config_manager.remove_app(app_key)
                self.selected_listbox.delete(selected[0])
                self.app_config_manager.save_config()
    
    def on_app_select(self, event):
        """当选择程序时加载自定义模板和默认示例"""
        selected = self.selected_listbox.curselection()
        if selected:
            display_text = self.selected_listbox.get(selected[0])
            
            # 从显示文本中提取app_key
            import re
            match = re.search(r'\(([^)]+)\)$', display_text)
            if not match:
                return
            
            app_key = match.group(1)
            
            # 获取应用分类和友好名称
            category = None
            friendly_name = None
            for cat, apps in self.monitor.app_parser.APP_CATEGORIES.items():
                if app_key in apps:
                    category = cat
                    friendly_name = apps[app_key]
                    break
            
            # 根据应用分类生成智能的默认模板
            if category == 'editors':
                default_template = "正在编辑 {file_name}"
                example_templates = [
                    "正在编辑 {file_name}",
                    "正在编辑 {file_name} ({project_name})",
                    "{appName} - {file_name}",
                    "{action} {file_name} 项目: {project_name}",
                ]
            elif category == 'browsers':
                default_template = "浏览 {page_title}"
                example_templates = [
                    "浏览 {page_title}",
                    "{appName} - {page_title}",
                    "正在浏览: {page_title}",
                    "{action}: {page_title}",
                ]
            elif category == 'music':
                default_template = "🎵 {song_name} - {artist}"
                example_templates = [
                    "🎵 {song_name} - {artist}",
                    "正在播放: {song_name}",
                    "{song_name} - {artist}",
                    "听歌中: {song_name}",
                ]
            elif category == 'video':
                default_template = "观看 {detail}"
                example_templates = [
                    "观看 {detail}",
                    "{appName} - {detail}",
                    "正在播放: {detail}",
                ]
            elif category == 'office':
                default_template = "编辑文档 {detail}"
                example_templates = [
                    "编辑文档 {detail}",
                    "{appName} - {detail}",
                    "{action} {detail}",
                ]
            else:
                # 通用默认模板
                default_template = "{appName} {action}: {detail}"
                example_templates = [
                    "{appName} {action}: {detail}",
                    "{appName} - {detail}",
                    "{action}: {detail}",
                ]
            
            # 显示默认模板示例
            if hasattr(self, 'default_text_label'):
                example_text = "\n".join(example_templates[:3])
                self.default_text_label.configure(text=example_text)
            
            # 加载自定义模板或显示智能默认模板
            if app_key in self.app_config_manager.monitored_apps:
                custom_template = self.app_config_manager.monitored_apps[app_key].get('custom_template', '')
                self.custom_text_var.set(custom_template if custom_template else default_template)
                
                # 加载自定义 action 设置
                custom_action = self.app_config_manager.monitored_apps[app_key].get('custom_action', '自动')
                self.action_var.set(custom_action)
            else:
                self.custom_text_var.set(default_template)
                self.action_var.set("自动")
    
    def apply_template(self, template):
        """应用快速模板"""
        self.custom_text_var.set(template)
    
    def test_push(self):
        """测试推送功能"""
        selected = self.selected_listbox.curselection()
        if not selected:
            self.logger.warning("⚠️ 请先选择要测试的应用")
            return
        
        display_text = self.selected_listbox.get(selected[0])
        
        # 提取 app_key
        import re
        match = re.search(r'\(([^)]+)\)$', display_text)
        if not match:
            self.logger.error("❌ 无法提取应用key")
            return
        
        app_key = match.group(1)
        
        # 构建测试数据
        test_status = {
            'active_app': f'Test - {display_text}',
            'timestamp': datetime.now().isoformat(),
            'computer_name': 'Test-PC',
            'appName': display_text.split('(')[0].strip(),
            'appIcon': 'test',
            'appType': 'app',
            'displayInfo': f'测试推送 - {display_text}',
            'action': '测试中',
        }
        
        try:
            # 调用监控器的推送方法
            if hasattr(self.monitor, 'send_status_to_web'):
                self.monitor.send_status_to_web(test_status)
                self.logger.info(f"✅ 已发送 {app_key} 的测试推送")
            else:
                self.logger.error("❌ 监控器未初始化")
        except Exception as e:
            self.logger.error(f"❌ 推送失败: {e}")
    
    def on_template_change(self, *args):
        """模板输入时实时预览"""
        try:
            template = self.custom_text_var.get()
            
            if not template:
                self.preview_label.configure(
                    text="💡 提示: 输入模板后按回车保存",
                    bootstyle="info"
                )
                return
            
            # 获取示例数据
            example_data = {
                'appName': 'Cursor',
                'action': '编辑',
                'detail': 'main.py',
                'file_name': 'main.py',
                'project_name': 'Blog',
                'page_title': '示例页面',
                'song_name': '示例歌曲',
                'artist': '示例歌手',
            }
            
            try:
                preview = template.format(**example_data)
                self.preview_label.configure(
                    text=f"✅ 预览: {preview}",
                    bootstyle="success"
                )
            except KeyError as e:
                self.preview_label.configure(
                    text=f"❌ 缺少占位符: {e}",
                    bootstyle="danger"
                )
            except Exception as e:
                self.preview_label.configure(
                    text=f"❌ 格式错误: {str(e)}",
                    bootstyle="danger"
                )
        except:
            pass
    
    def save_custom_text(self, event=None):
        """保存自定义模板"""
        # 检查 listbox 是否存在
        if not hasattr(self, 'selected_listbox'):
            return
        
        selected = self.selected_listbox.curselection()
        
        # 如果没有选中，尝试获取最后一个添加的项
        if not selected:
            size = self.selected_listbox.size()
            if size > 0:
                # 获取最后一项
                last_index = size - 1
                self.selected_listbox.selection_set(last_index)
                selected = (last_index,)
            else:
                self.logger.warning("⚠️ 请先添加要配置的应用")
                return
        
        if not hasattr(self, 'custom_text_var'):
            return
        
        display_text = self.selected_listbox.get(selected[0])
        
        # 从显示文本中提取app_key
        import re
        match = re.search(r'\(([^)]+)\)$', display_text)
        if not match:
            return
        
        app_key = match.group(1)
        custom_template = self.custom_text_var.get()
        
        if app_key in self.app_config_manager.monitored_apps:
            self.app_config_manager.set_custom_template(app_key, custom_template)
            
            # 保存 action 设置
            action_value = self.action_var.get()
            if action_value != "自动":
                self.app_config_manager.monitored_apps[app_key]['custom_action'] = action_value
            else:
                # 移除自定义 action，使用自动识别
                self.app_config_manager.monitored_apps[app_key].pop('custom_action', None)
            
            self.app_config_manager.save_config()
            self.logger.info(f"✅ 已保存 {app_key} 的自定义模板")
        else:
            self.logger.error(f"❌ {app_key} 不在已监控应用列表中")
    
    def create_connection_tab(self, parent):
        """创建连接设置标签页"""
        tab = ttk.Frame(parent, padding=12)
        parent.add(tab, text="🌐 连接设置")
        
        # 服务器地址卡片
        server_frame = ttk.Labelframe(
            tab,
            text="服务器配置",
            padding=12,
            bootstyle="info"
        )
        server_frame.pack(fill=X, pady=(0, 10))
        
        ttk.Label(
            server_frame,
            text="Socket.IO 服务器地址",
            font=("Microsoft YaHei UI", 10, "bold")
        ).pack(anchor=W, pady=(0, 8))
        
        server_url = self.config.get('SERVER', 'server_url', fallback='http://localhost:3001')
        self.server_url_var = ttk.StringVar(value=server_url)
        
        server_entry = ttk.Entry(
            server_frame,
            textvariable=self.server_url_var,
            font=("Consolas", 10),
            bootstyle="info"
        )
        server_entry.pack(fill=X, pady=(0, 10))
        
        # 快捷设置按钮
        quick_buttons = ttk.Frame(server_frame)
        quick_buttons.pack(fill=X)
        
        ttk.Button(
            quick_buttons,
            text="本地 :3001",
            command=lambda: self.server_url_var.set('http://localhost:3001'),
            bootstyle="secondary-outline",
            width=12
        ).pack(side=LEFT, padx=(0, 8))
        
        ttk.Button(
            quick_buttons,
            text="本地 :8200",
            command=lambda: self.server_url_var.set('http://localhost:8200'),
            bootstyle="secondary-outline",
            width=12
        ).pack(side=LEFT)
        
        ttk.Button(
            quick_buttons,
            text="🔍 测试连接",
            command=self.test_connection,
            bootstyle="primary",
            width=12
        ).pack(side=RIGHT)
        
        # 功能说明卡片
        info_frame = ttk.Labelframe(
            tab,
            text="功能特性",
            padding=12,
            bootstyle="secondary"
        )
        info_frame.pack(fill=X)
        
        features = [
            "🔹 实时监控窗口切换，智能识别应用类型",
            "🔹 支持编辑器、浏览器、音乐播放器等多种应用",
            "🔹 Socket.IO 低延迟实时推送",
            "🔹 自动重连和断线恢复机制",
            "🔹 2秒防抖动，避免频繁推送"
        ]
        
        for feature in features:
            ttk.Label(
                info_frame,
                text=feature,
                font=("Microsoft YaHei UI", 9),
                bootstyle="secondary"
            ).pack(anchor=W, pady=2)
    
    def create_log_tab(self, parent):
        """创建实时日志标签页"""
        tab = ttk.Frame(parent, padding=12)
        parent.add(tab, text="📊 实时日志")
        
        # 日志控制栏
        header = ttk.Frame(tab)
        header.pack(fill=X, pady=(0, 10))
        
        ttk.Label(
            header,
            text="运行日志",
            font=("Microsoft YaHei UI", 12, "bold")
        ).pack(side=LEFT)
        
        ttk.Button(
            header,
            text="🗑️ 清空日志",
            command=self.clear_logs,
            bootstyle="warning-outline",
            width=12
        ).pack(side=RIGHT)
        
        # 日志显示区域 - 使用scrolledtext
        log_frame = ttk.Frame(tab)
        log_frame.pack(fill=BOTH, expand=YES)
        
        self.log_text = scrolledtext.ScrolledText(
            log_frame,
            font=("Consolas", 9),
            wrap="word",
            bg="#1e1e1e",
            fg="#d4d4d4",
            insertbackground="#ffffff"
        )
        self.log_text.pack(fill=BOTH, expand=YES)
        
        # 加载最近的日志
        self.load_recent_logs()
    
    def create_about_tab(self, parent):
        """创建关于标签页"""
        tab = ttk.Frame(parent, padding=30)
        parent.add(tab, text="ℹ️ 关于")
        
        # 应用信息卡片
        about_frame = ttk.Labelframe(
            tab,
            text="应用信息",
            padding=20,
            bootstyle="primary"
        )
        about_frame.pack(fill=BOTH, expand=YES)
        
        # 标题
        ttk.Label(
            about_frame,
            text="拾取窗中流光",
            font=("Microsoft YaHei UI", 16, "bold"),
            bootstyle="primary"
        ).pack(pady=(0, 5))
        
        ttk.Label(
            about_frame,
            text="v2.0",
            font=("Microsoft YaHei UI", 10),
            bootstyle="secondary"
        ).pack(pady=(0, 15))
        
        # 描述
        ttk.Label(
            about_frame,
            text="✨ 智能窗口状态推送工具",
            font=("Microsoft YaHei UI", 11, "bold")
        ).pack(pady=(0, 10))
        
        # 功能列表
        features = """
🚀 核心功能
• 实时监控窗口切换
• 智能识别应用类型（编辑器/浏览器/音乐等）
• 自动提取关键信息（文件名/页面标题/歌曲名）
• Socket.IO 实时推送

🎯 技术特性
• 2秒防抖动机制
• 自动重连和断线恢复
• 完整的日志系统
• 低资源占用

💡 快速开始
1. 配置服务器地址
2. 点击"开始监控"
3. 在博客查看实时状态
        """
        
        ttk.Label(
            about_frame,
            text=features,
            font=("Microsoft YaHei UI", 9),
            justify=LEFT,
            bootstyle="secondary"
        ).pack(fill=BOTH, expand=YES, pady=10)
        
        # 底部信息
        ttk.Label(
            about_frame,
            text="作者: adnaan  |  使用 ttkbootstrap 构建",
            font=("Microsoft YaHei UI", 8),
            bootstyle="secondary"
        ).pack(pady=(10, 0))
    
    def start_log_updates(self):
        """开始日志更新"""
        self.update_logs()
        self.update_status_display()
    
    def update_logs(self):
        """更新日志显示"""
        if self.log_text:
            try:
                while not self.log_manager.log_queue.empty():
                    try:
                        log_entry = self.log_manager.log_queue.get_nowait()
                        self.log_text.insert("end", log_entry + "\n")
                        self.log_text.see("end")
                        
                        # 限制日志行数
                        lines = self.log_text.get("1.0", "end").count('\n')
                        if lines > 1000:
                            for _ in range(100):
                                self.log_text.delete("1.0", "2.0")
                                
                    except queue.Empty:
                        break
            except Exception:
                pass
        
        if hasattr(self.window, 'winfo_exists') and self.window.winfo_exists():
            self.window.after(500, self.update_logs)
    
    def update_status_display(self):
        """更新状态显示 - 清新简约界面（优化版）"""
        try:
            # 获取统计信息
            stats = self.monitor.get_statistics()
            
            # 更新状态标签
            if hasattr(self, 'status_label'):
                if self.monitor.running:
                    self.status_label.configure(text="🟢 监控已启动", bootstyle="success")
                else:
                    self.status_label.configure(text="🔴 监控已停止", bootstyle="danger")
            
            # 更新按钮
            if hasattr(self, 'start_btn'):
                if self.monitor.running:
                    self.start_btn.configure(text="⏸️ 暂停", bootstyle="warning-outline")
                else:
                    self.start_btn.configure(text="▶️ 开始", bootstyle="success-outline")
            
            # 更新推送统计
            if hasattr(self, 'push_count_label'):
                success_rate = stats.get('success_rate', 0)
                push_count = stats.get('push_count', 0)
                self.push_count_label.configure(
                    text=f"📊 推送: {push_count} 次 | 成功率: {success_rate:.0f}%"
                )
            
            # 更新运行时长
            if hasattr(self, 'uptime_label'):
                uptime = stats.get('uptime', 0)
                if uptime < 60:
                    uptime_str = f"{int(uptime)}秒"
                elif uptime < 3600:
                    uptime_str = f"{int(uptime/60)}分钟"
                else:
                    hours = int(uptime / 3600)
                    minutes = int((uptime % 3600) / 60)
                    uptime_str = f"{hours}小时{minutes}分"
                
                self.uptime_label.configure(text=f"⏱️ 运行: {uptime_str}")
            
            if hasattr(self.window, 'winfo_exists') and self.window.winfo_exists():
                self.window.after(1000, self.update_status_display)
        except Exception as e:
            pass
    
    def load_recent_logs(self):
        """加载最近的日志"""
        recent_logs = self.log_manager.get_recent_logs(50)
        for log_entry in recent_logs:
            self.log_text.insert("end", log_entry + "\n")
        self.log_text.see("end")
    
    def clear_logs(self):
        """清空日志"""
        if self.log_text:
            self.log_text.delete("1.0", "end")
            self.logger.info("🗑️ 日志已清空")
    
    def test_connection(self):
        """测试Socket.IO连接"""
        def test_in_thread():
            try:
                server_url = self.server_url_var.get().strip()
                if not server_url:
                    self.logger.error("❌ 请先设置服务器地址")
                    messagebox.showerror("错误", "请先设置服务器地址")
                    return
                
                self.logger.info("🔄 正在测试Socket.IO连接...")
                
                import requests
                response = requests.get(f"{server_url}/socket.io/", timeout=10, params={'transport': 'polling'})
                
                if response.status_code == 200:
                    self.logger.info("✅ Socket.IO连接测试成功")
                    
                    # 使用ttkbootstrap的Toast通知
                    toast = ToastNotification(
                        title="连接成功",
                        message="Socket.IO 服务器连接正常",
                        duration=3000,
                        bootstyle="success"
                    )
                    toast.show_toast()
                else:
                    self.logger.error(f"❌ 连接测试失败 - 状态码: {response.status_code}")
                    messagebox.showwarning("警告", f"连接测试失败\n状态码: {response.status_code}")
                
            except Exception as e:
                self.logger.error(f"❌ 测试失败: {e}")
                messagebox.showerror("错误", f"连接失败: {e}")
        
        threading.Thread(target=test_in_thread, daemon=True).start()
    
    def toggle_monitoring(self):
        """切换监控状态"""
        if self.monitor.running:
            self.monitor.stop_monitoring()
        else:
            # 检查是否有已选程序
            if not self.app_config_manager.monitored_apps:
                messagebox.showwarning("警告", "请先在应用管理中选择要监控的程序")
                return
            
            success = self.monitor.start_monitoring()
            if not success:
                messagebox.showerror("错误", "无法启动监控，请检查网络连接和配置")
    
    def save_config(self):
        """保存配置"""
        try:
            server_url = self.server_url_var.get().strip()
            if not server_url:
                messagebox.showerror("错误", "请输入服务器地址")
                return
            
            if 'SERVER' not in self.config:
                self.config['SERVER'] = {}
            
            self.config['SERVER']['server_url'] = server_url
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                self.config.write(f)
            
            self.logger.info("✅ 配置已保存")
            
            toast = ToastNotification(
                title="保存成功",
                message="配置已成功保存",
                duration=2000,
                bootstyle="success"
            )
            toast.show_toast()
            
        except Exception as e:
            self.logger.error(f"❌ 保存配置失败: {e}")
            messagebox.showerror("错误", f"保存失败: {e}")
    
    def center_window(self):
        """居中显示窗口"""
        self.window.update_idletasks()
        width = self.window.winfo_width()
        height = self.window.winfo_height()
        
        # 获取屏幕尺寸
        screen_width = self.window.winfo_screenwidth()
        screen_height = self.window.winfo_screenheight()
        
        # 计算居中位置
        x = (screen_width // 2) - (width // 2)
        y = (screen_height // 2) - (height // 2)
        
        self.window.geometry(f"+{x}+{y}")
    
    def start_drag(self, event):
        """开始拖动窗口"""
        self.drag_x = event.x_root
        self.drag_y = event.y_root
    
    def on_drag(self, event):
        """拖动窗口"""
        x = self.window.winfo_x() + (event.x_root - self.drag_x)
        y = self.window.winfo_y() + (event.y_root - self.drag_y)
        self.window.geometry(f"+{x}+{y}")
        self.drag_x = event.x_root
        self.drag_y = event.y_root
    
    def hide_window(self):
        """隐藏窗口到托盘"""
        self.window.withdraw()
        self.logger.info("🔽 窗口已隐藏到托盘")
    
    def run(self):
        """运行配置窗口 - 开始事件循环"""
        # 开始窗口更新
        self.update_logs()
        self.update_status_display()
        
        # Toplevel 窗口会自动参与父窗口的事件循环
        # 不需要单独的 mainloop()


class ModernSystemTrayApp:
    """现代化系统托盘应用"""
    
    def __init__(self):
        self.log_manager = LogManager()
        self.logger = self.log_manager.get_logger()
        # 先创建monitor，它会创建带parser的app_config_manager
        self.monitor = StatusMonitor(self.log_manager)
        # 引用monitor的配置管理器
        self.app_config_manager = self.monitor.app_config_manager
        self.icon = None
        self.config_window = None
        self.root_window = None  # 隐藏的根窗口
        self._icon_image = None  # 缓存图标图像
        self._icon_loaded = False  # 标记图标是否已加载
        
        self.logger.info("🚀 系统托盘应用初始化")
    
    def create_icon_image(self):
        """创建托盘图标"""
        # 首次加载时尝试从文件加载
        if not self._icon_loaded:
            try:
                # 处理打包后的图标路径
                if getattr(sys, 'frozen', False):
                    # 打包后的可执行文件
                    icon_path = Path(sys.executable).parent / 'icon.ico'
                else:
                    # 开发环境
                    icon_path = Path(__file__).parent / 'icon.ico'
                
                if icon_path.exists():
                    self.logger.info(f"✅ 找到图标文件: {icon_path}")
                    self._icon_image = Image.open(icon_path)
                    self._icon_loaded = True
                    return self._icon_image
                else:
                    self.logger.warning(f"⚠️ 图标文件不存在: {icon_path}")
            except Exception as e:
                self.logger.warning(f"加载图标失败: {e}")
            
            self._icon_loaded = True  # 标记已尝试加载
        
        # 如果已有缓存的图标，直接返回
        if self._icon_image:
            return self._icon_image
        
        # 创建现代化图标（带状态指示器）
        img = Image.new('RGBA', (64, 64), (0, 0, 0, 0))
        draw = ImageDraw.Draw(img)
        
        # 绘制渐变圆形图标
        draw.ellipse([4, 4, 60, 60], fill=(102, 126, 234, 255), outline=(118, 75, 162, 255), width=3)
        draw.ellipse([20, 20, 44, 44], fill=(255, 255, 255, 255))
        draw.ellipse([24, 24, 40, 40], fill=(102, 126, 234, 255))
        
        # 状态指示器（动态变化）
        if hasattr(self, 'monitor') and self.monitor and self.monitor.running:
            draw.ellipse([45, 8, 58, 21], fill=(76, 175, 80, 255))
        else:
            draw.ellipse([45, 8, 58, 21], fill=(244, 67, 54, 255))
        
        return img
    
    def create_menu(self):
        """创建托盘菜单（简化版）"""
        return pystray.Menu(
            pystray.MenuItem("显示窗口", self.show_config, default=True),
            pystray.MenuItem("退出", self.quit_app)
        )
    
    def update_menu(self):
        """更新托盘菜单"""
        if self.icon:
            self.icon.menu = self.create_menu()
            # 如果没有静态图标文件，则动态更新图标状态指示器
            if not self._icon_image:
                self.icon.icon = self.create_icon_image()
    
    def toggle_monitoring(self, icon=None, item=None):
        """切换监控状态"""
        if self.monitor.running:
            self.monitor.stop_monitoring()
            self.show_notification("已停止监控", "")
        else:
            success = self.monitor.start_monitoring()
            if success:
                self.show_notification("已开始监控", "")
            else:
                self.show_notification("启动失败", "请检查网络连接")
        
        self.update_menu()
    
    def show_config(self, icon=None, item=None):
        """显示配置界面"""
        try:
            if self.config_window is None or not hasattr(self.config_window.window, 'winfo_exists') or not self.config_window.window.winfo_exists():
                self.logger.info("🎨 打开控制面板")
                
                # 使用root_window的after方法在主线程中创建窗口
                def create_config_in_main_thread():
                    try:
                        self.config_window = ModernConfigWindow(
                            self.monitor, 
                            self.log_manager, 
                            self.root_window
                        )
                        # 开始窗口更新
                        self.config_window.update_logs()
                        self.config_window.update_status_display()
                    except Exception as e:
                        self.logger.error(f"❌ 控制面板启动失败: {e}")
                        self.show_notification("控制面板启动失败", str(e))
                
                # 调度到主线程
                if self.root_window:
                    self.root_window.after(0, create_config_in_main_thread)
                else:
                    # 如果root_window不存在，直接创建
                    create_config_in_main_thread()
            else:
                # 窗口已存在，只显示
                if self.config_window and hasattr(self.config_window, 'window'):
                    try:
                        self.config_window.window.deiconify()
                        self.config_window.window.lift()
                        self.config_window.window.focus_force()
                    except Exception as e:
                        self.logger.error(f"显示窗口失败: {e}")
        except Exception as e:
            self.logger.error(f"❌ 打开控制面板失败: {e}")
            self.show_notification("打开失败", str(e))
    
    def show_current_status(self, icon=None, item=None):
        """显示当前状态"""
        status = self.monitor.current_status
        
        active_app = status.get('active_app', '无活动')
        timestamp = status.get('timestamp', '无')
        
        if len(active_app) > 60:
            active_app = active_app[:57] + "..."
        
        socket_status = "已连接" if self.monitor.socket_connected else "未连接"
        monitor_status = "运行中" if self.monitor.running else "已停止"
        
        message = f"""📊 当前状态
🖥️ 活动应用: {active_app}
🔌 Socket.IO: {socket_status}
📡 监控状态: {monitor_status}
⏰ 最后更新: {timestamp.split('T')[1][:8] if 'T' in timestamp else timestamp}"""
        
        self.show_notification("当前状态", message)
    
    def show_notification(self, title, message):
        """显示通知"""
        try:
            if self.icon:
                # 限制消息长度
                if len(message) > 200:
                    message = message[:197] + "..."
                self.icon.notify(message, title)
                self.logger.info(f"📢 通知: {title}")
        except Exception as e:
            self.logger.warning(f"通知显示失败: {e}")
    
    def update_tooltip(self):
        """更新托盘图标提示"""
        try:
            if self.icon:
                stats = self.monitor.get_statistics()
                status = "运行中" if self.monitor.running else "已停止"
                tooltip = f"拾取窗中流光 - {status}\n推送: {stats['push_count']}次"
                self.icon.title = tooltip
        except Exception:
            pass
    
    def quit_app(self, icon=None, item=None):
        """退出应用（优化版）"""
        self.logger.info("🚪 正在退出应用...")
        
        # 停止监控
        try:
            self.monitor.stop_monitoring()
        except Exception as e:
            self.logger.error(f"停止监控时出错: {e}")
        
        # 保存配置
        try:
            self.app_config_manager.save_config()
        except Exception as e:
            self.logger.error(f"保存配置时出错: {e}")
        
        # 关闭配置窗口
        try:
            if self.config_window and hasattr(self.config_window, 'window'):
                self.config_window.window.after(0, self.config_window.window.destroy)
        except Exception as e:
            self.logger.warning(f"关闭配置窗口时出错: {e}")
        
        # 停止托盘图标
        try:
            if self.icon:
                self.icon.stop()
        except Exception as e:
            self.logger.warning(f"停止托盘图标时出错: {e}")
        
        # 显示退出统计
        try:
            stats = self.monitor.get_statistics()
            self.logger.info(f"📊 会话统计: 推送 {stats['push_count']} 次, "
                           f"应用切换 {stats['app_switches']} 次")
        except:
            pass
        
        self.logger.info("👋 应用已退出")
        
        # 强制退出
        try:
            import os
            os._exit(0)
        except:
            sys.exit(0)
    
    def run(self):
        """运行托盘应用"""
        try:
            # 创建隐藏的根窗口用于Tkinter
            self.root_window = ttk.Window(themename="darkly")
            self.root_window.withdraw()  # 隐藏窗口
            
            # 创建托盘图标，双击打开窗口
            self.icon = pystray.Icon(
                "LightCapture",
                self.create_icon_image(),
                "✨ 拾取窗中流光 v2.0",
                self.create_menu()
            )
            
            # 设置双击事件：打开控制面板
            self.icon.default_action = self.show_config
            
            # 定期更新托盘提示
            def update_tooltip_periodically():
                while True:
                    time.sleep(10)  # 每10秒更新一次
                    if self.icon:
                        try:
                            self.update_tooltip()
                        except:
                            break
            
            threading.Thread(target=update_tooltip_periodically, daemon=True).start()
            
            # 自动启动监控
            threading.Timer(2.0, self.monitor.start_monitoring).start()
            
            self.logger.info("✅ 托盘应用启动成功")
            
            # 在单独的线程中运行托盘（因为run()是阻塞的）
            def run_tray():
                self.icon.run()
            
            threading.Thread(target=run_tray, daemon=True).start()
            
            # 运行Tkinter主循环
            self.root_window.mainloop()
            
        except Exception as e:
            self.logger.error(f"❌ 托盘应用启动失败: {e}")
            messagebox.showerror("启动失败", f"应用启动失败: {e}")


def main():
    """主函数"""
    print("=" * 50)
    print("✨ 拾取窗中流光 v2.0")
    print("=" * 50)
    print("🚀 启动中...")
    print("💡 程序将在系统托盘运行")
    print("🖱️ 右键托盘图标打开菜单")
    print("=" * 50)
    
    try:
        app = ModernSystemTrayApp()
        app.run()
    except Exception as e:
        print(f"❌ 应用启动失败: {e}")
        messagebox.showerror("启动失败", f"应用启动失败: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
